/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp._134_;


import cz.pecinovsky.english.lootp.manager.Painter;


import cz.pecinovsky.english.lootp.manager.CanvasManager_Envelope.               CanvasManager;




import cz.pecinovsky.english.lootp._134_.IModular_134_.IModular;
//import cz.pecinovsky.english.lootp._134_.Ring_134_.Ring;
import cz.pecinovsky.english.lootp._134_.RoadField_134_.RoadField;
import cz.pecinovsky.english.lootp._134_.StavitelOkruhů_134_ .StavitelOkruhů;


//import cz.pecinovsky.english.lootp._134_.Ring_134_.Ring;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++
//%I+ >141
//
//import cz.pecinovsky.english.lootp.canvasmanager.Painter;
//import cz.pecinovsky.english.lootp.canvasmanager.CanvasManager;
//%I-

import cz.pecinovsky.english.lootp.utility.NamedColor;
import cz.pecinovsky.english.lootp.utility.Position;
//%A+ >140
import cz.pecinovsky.english.lootp.utility.Size;
//%A-


import static cz.pecinovsky.english.lootp.utility.Direction8.*;

//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   Není - toto_je_nově_definovaná_třída
 *              Ttt v projektu Ppp
 * Následující: Prozatím není
 *
 * Projekt  140
 *  + pRozměr
 *  + rpPozicePočátku
 *  + getPRozměr()
 *  + getRPPozicePočátku
 *  - Odebráno
 *  ~ Změněno
 *</pre>
 */
public class Ring_134_
{    private Ring_134_() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- End of the ovejumped text with declaration of the envelope -----


/*******************************************************************************
 * Instance třídy {@code Ring} představují okružní trasy,
 * po kterých je možné cestovat nebo závodit.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
//%I+ <141
//public class Ring
//%I-
//%A+ >141
public class Ring implements IModular
//%A-
{
//== CONSTANT CLASS ATTRIBUTES =================================================
//%A+ >141

    /** Canvas, na které se bude instance kreslit. */
    private static final CanvasManager CM = CanvasManager.getInstance();



//%A-
//== VARIABLE CLASS ATTRIBUTES =================================================
//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ========
//== CONSTANT INSTANCE ATTRIBUTES ==============================================
//== VARIABLE INSTANCE ATTRIBUTES ==============================================

    /** Počáteční blok cesty. Je-li cesta uzavřená, je shodný s koncovým. */
    private RoadField počátek;
//%A+ >140

    /** Relativní políčková pozicePole počátku vůči pozici obdélníka
     *  definujícího zabranou oblast. */
    Position rpPozicePočátku = null;

    /** Políčkový rozměr okruhu je definován rozměrem nejmenšího obdélníku,
     *  do kterého se okruh vejde. */
    Size pRozměr = null;
//%A-
//%A+ >141

    /** Bodová pozicePole oblasti zaujímané okruhem. */
    private Position poziceOkruhu;

//%A-



//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

    /***************************************************************************
     * Vytvoří na zadané pozici nejmenší možný okruh.
     * Ring je čtvercový, má implicitní, tj. šedou barvu
     * a vyráží se z levého horního rohu směrem na východ.
     *
     * @param startPosition Position startovního pole okruhu
     * @return Vytvořený okruh
     */
    public static Ring čtverec(Position startPosition)
    {
        StavitelOkruhů builder = new StavitelOkruhů(startPosition);
        builder.zahajNa   (EAST);
        builder.pokračujNa(SOUTH);
        builder.pokračujNa(WEST);
        builder.closeTo  (NORTH);
        return builder.getOkruh();
    }


    /***************************************************************************
     * Vytvoří na zadané pozici malý okruh zadané barvy ve tvaru velkého L.
     * Po okruhu se vyráží z levého horního rohu směrem na jih.
     *
     * @param startPosition Position startovního pole okruhu
     * @param color       NamedColor budovaného okruhu
     * @return Vytvořený okruh
     */
    public static Ring elko(Position startPosition, NamedColor color)
    {
        StavitelOkruhů builder = new StavitelOkruhů(startPosition, color);
        builder.zahajNa   (SOUTH);
        builder.pokračujNa(SOUTH);
        builder.pokračujNa(SOUTH);
        builder.pokračujNa(EAST);
        builder.pokračujNa(EAST);
        builder.pokračujNa(EAST);
        builder.pokračujNa(NORTH);
        builder.pokračujNa(NORTH);
        builder.pokračujNa(WEST);
        builder.pokračujNa(NORTH);
        builder.pokračujNa(WEST);
        builder.closeTo  (WEST);
        return builder.getOkruh();
    }

//%A+ <0

    /***************************************************************************
     * Vytvoří okruh śedé barvy okolo celého dvorku.
     *
     * @return Vytvořený okruh
     */
    public static Ring okolo()
    {
        StavitelOkruhů builder = new StavitelOkruhů(new Position(0, 0), NamedColor.GRAY);
        builder.zahajNa   (SOUTH);
        builder.pokračujNa(SOUTH);       builder.pokračujNa(SOUTH);
        builder.pokračujNa(SOUTH);       builder.pokračujNa(SOUTH);

        builder.pokračujNa(EAST);    builder.pokračujNa(EAST);
        builder.pokračujNa(EAST);    builder.pokračujNa(EAST);
        builder.pokračujNa(EAST);
        builder.pokračujNa(NORTH);     builder.pokračujNa(NORTH);
        builder.pokračujNa(NORTH);     builder.pokračujNa(NORTH);
        builder.pokračujNa(NORTH);
        builder.pokračujNa(WEST);     builder.pokračujNa(WEST);
        builder.pokračujNa(WEST);     builder.pokračujNa(WEST);
        builder.closeTo  (WEST);
        return builder.getOkruh();
    }

//%A-

//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * Na zadané pozici založí novou cestu implicitní barvy
     * vyrážející zadaným směrem a vytvoří její první blok.
     *
     * @param počátek  Position počátečního bloku
     */
    public Ring(RoadField počátek)
    {
        this.počátek = počátek;
    }



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================

    /***************************************************************************
     * Vrátí počáteční blok dané cesty.
     *
     * @return Počáteční blok cesty
     */
    public RoadField getPočátek()
    {
        return počátek;
    }

//%A+ >141

    /***************************************************************************
     * Vrátí relativní políčkovou pozici počátku okruhu,
     * tj. pozici startovního pole měřenou relativně k počátku oblasti,
     * kterou daný okruh zaujímá, měřenou v políčcích.
     *
     * @return Relativní políčková pozicePole počátku okruhu
     */
    public Position getRPPozicePočátku()
    {
        if (rpPozicePočátku == null) {
            getPRozměr();   //Metoda zjišťuje současně pRozměr i rpPočátek
        }
        return rpPozicePočátku;
    }


    /***************************************************************************
     * Vrátí políčkový rozměr okruhu, (rozměr měřený v políčcích), čímž se
     * rozumí rozměr nejmenšího obdélníku, do nějž se okruh vejde.
     * Metoda počítá rozměr a relativní políčkovou pozici počátku, ale pouze
     * při prvním zavolání. Při dalších voláních si již tyto údaje bere
     * z atributu, takže další dotazy již program nezdržují.
     *
     * @return Požadovaný rozměr
     */
    public Size getPRozměr()
    {
        if (pRozměr == null) {
            RoadField pole       = počátek;
            Position    pozicePole = počátek.getPosition();
            int minx = pozicePole.x;
            int miny = pozicePole.y;
            int maxx = minx;
            int maxy = miny;
            for (;;) {
                //Příprava dalších hodnot parametrů
                pole       = pole.getDalší();
                pozicePole = pole.getPosition();
                if (pole == počátek) {  //Ring je již oběhnut
                    break;              //---------->
                }
                //Test vodorovné souřadnice
                if (pozicePole.x < minx) {
                    minx = pozicePole.x;
                } else if (pozicePole.x > maxx) {
                    maxx = pozicePole.x;
                }
                //Test svislé souřadnice
                if (pozicePole.y < miny) {
                    miny = pozicePole.y;
                } else if (pozicePole.y > maxy) {
                    maxy = pozicePole.y;
                }
            }
            //Krajní bodové souřadnice známe, můžeme je přepočítat na políčkové
            int module = pole.getModule();
            pRozměr = new Size((maxx - minx)/module + 1,
                                 (maxy - miny)/module + 1);
            rpPozicePočátku = new Position((pozicePole.x - minx)/module,
                                         (pozicePole.y - miny)/module);
        }
        return pRozměr;
    }


    /***************************************************************************
     * Vrátí přepravku se souřadnicemi instance.
     *
     * @return  Přepravka se souřadnicemi instance
     */
     @Override
    public Position getPosition()
    {
        if (this.poziceOkruhu == null) {
            getPRozměr();   //Metoda zjišťuje současně pRozměr i rpPočátek
        }
        int module = getModule();
        Position pozicePočátku = počátek.getPosition();
        int x = pozicePočátku.x  -  rpPozicePočátku.x * module;
        int y = pozicePočátku.y  -  rpPozicePočátku.y * module;
        this.poziceOkruhu = new Position(x, y);
        return this.poziceOkruhu;
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param nováPozice  Nová pozicePole instance
     */
    @Override
    public void setPosition(Position nováPozice)
    {
        setPosition(nováPozice.x, nováPozice.y);
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová pozicePole instance
     * @param y   Nová y-ová pozicePole instance
     */
    @Override
    public void setPosition(int x, int y)
    {
        int dx = x  -  poziceOkruhu.x;
        int dy = y  -  poziceOkruhu.y;
        RoadField pole = počátek;
        Position pozicePole;
        CM.dontDraw(); {
            do {
                pozicePole = pole.getPosition();
                pole.setPosition(pozicePole.x + dx, pozicePole.y + dy);
                pole = pole.getDalší();
            } while (pole != počátek);
            this.poziceOkruhu = new Position(x, y);
        } CM.returnDraw();
    }


    /***************************************************************************
     * Vrátí základní délku, od níž se odvozují všechny rozměry objektu.
     *
     * @return Velikost modulu
     */
    @Override
    public int getModule() {
        return počátek.getModule();
    }


    /***************************************************************************
     * Nastaví nový základní rozměr objektu,
     * od nějž se odvozují jeho ostatní rozměry.
     *
     * @param novýModul Nově nastavovaný novýModul
     */
    @Override
    public void setModule(int novýModul) {
        if (this.poziceOkruhu == null) {
            getPosition();
        }
        //Spočte současnou políčkovou pozici
        int starýModul = getModule();

        CM.dontDraw(); {
            //Nastaví všem polím nový novýModul a pozici
            RoadField pole = počátek;
            do {
                Position pozicePole = pole.getPosition();

                //Zjistí jejich políčkovou pozici
                int px = pozicePole.x / starýModul;
                int py = pozicePole.y / starýModul;

                //Z políčkové pozicePole odvodí bodovou pozici při novém modulu
                pole.setPosition(px*novýModul, py*novýModul);

                pole.setModule(novýModul);
                pole = pole.getDalší();
            } while (pole != počátek);
        } CM.returnDraw();
    }


    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param painter Painter, které nakreslí instanci
     */
    @Override
    public void paint(Painter painter)
    {
        RoadField pole = počátek;
        do {
            pole.paint(painter);
            pole = pole.getDalší();
        } while (pole != počátek);
    }

//%A-


//%X+
    @Override public int getX() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    @Override public int getY() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
//%X-
//== OTHER NON-PRIVATE INSTANCE METHODS ========================================

    /***************************************************************************
     * Vrací textovou reprezentaci (podpis) dané instance
     * používanou především k ladicím účelům.
     *
     * @return Požadovaná textová reprezentace
     */
    @Override
    public String toString()
    {
        return "Okruh_(počátek=" + počátek + ")";
    }



//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== EMBEDDED TYPES AND INNER CLASSES ==========================================
//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Test method.
//     */
//    public static void test()
//    {
//        Ring inst = new Ring();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main(String[] args)  {  test();  }
    }

//%%- ---- Start of the ovejumped text with closing of the envelope ----
////////////////////////////////////////////////////////////////////////////////
//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Test method.
//     */
//    public static void test()
//    {
//        System.exit(0);
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main(String[] args)  {  test();  }
}
